<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Robot\Robot;
use App\CustHub\Amqp\Producers\SyncTaskProducers;
use App\CustHub\Constants\ContactBehaviorTypeConstants;
use App\CustHub\Constants\ContactTaskCenterTyperConstants;
use App\CustHub\Constants\SyncTaskStatusConstants;
use App\CustHub\Constants\CorpTagTypeConstants;
use App\CustHub\Constants\SyncTaskTypeConstants;
use App\CustHub\Dto\ContactTcContentDto;
use App\CustHub\Dto\SyncTaskDto;
use App\CustHub\Event\ContactOperationBehaviorAfter;
use App\CustHub\Mapper\ChCorpMapper;
use App\CustHub\Mapper\ChCorpTagMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSyncTaskMapper;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChCorp;
use App\CustHub\Model\ChCorpTag;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChSyncTask;
use App\Robot\Service\RobotApiService;
use Hyperf\Amqp\Producer;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;
use function Hyperf\Collection\collect;

class ChCorpTagService extends AbstractService
{
    public $mapper;

    #[Inject]
    protected ChCorpMapper $corpMapper;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChSyncTaskMapper $syncTaskMapper;

    public function __construct(ChCorpTagMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    public function corpTagList(array $params)
    {
        if(!empty($params['corp_id'])){
            $corpId = $params['corp_id'];
        }elseif(!empty($params['robot_id'])){
            $robotInfo = $this->robotMapper->findById($params['robot_id']);
            $corpId = $robotInfo->corp_id;
        }else{
            throw new NormalStatusException('请选择企业或者企微号');
        }

        $corpInfo = ChCorp::query()->where('id',$corpId)->first();
        $list = $this->mapper->getListByCorpId($corpInfo->corp_id);
        return arrayToTree($list, 0, 'id', 'group_id');
    }

    public function personalTagList(array $params)
    {
        $list = $this->mapper->getListByRobotId($params['robot_id']);
        return arrayToTree($list, 0, 'id', 'group_id');
    }

    public function selectList(array $params)
    {
        $corpInfo = ChCorp::query()->where('id',$params['corp_id'])->first();

        if(empty($corpInfo)){
            throw new NormalStatusException('请选择企业');
        }

        $list = ChCorpTag::query()
            ->select(['id', 'name', 'group_id'])
            ->where('corp_id', $corpInfo->corp_id)
            ->when(!empty($params['name']),function ($query) use ($params){
                $query->where('name', 'like', '%'.$params['name'].'%');
            })
            ->where('label_type',1)
            ->orderBy('create_time', 'desc')
            ->get()->toArray();

        return arrayToTree($list, 0, 'id', 'group_id');
    }

    /**
     * 同步企业标签
     * @param array $params
     * @return bool
     */
    public function syncCorpTag(array $params): bool
    {
        $corpId = $params['corp_id'];
        $corpInfo = $this->corpMapper->findById($corpId);

        if (empty($corpInfo)) {
            return false;
        }

        //获取一个在线的企微号
        $robotInfo = ChRobot::query()
            ->select(['id', 'server_id', 'robot_key'])
            ->where('corp_id', $corpId)
            ->where('login_status', 1)
            ->first();
        if (empty($robotInfo)) {
            throw new NormalStatusException('企微号离线，不能同步标签');
        }

        $type = CorpTagTypeConstants::CORP;

        //检查是否存在进行中的任务
        if($this->syncTaskMapper->checkIsTaskInProgress($corpId,$type,true)){
            throw new NormalStatusException('标签正在同步中，请稍后再试');
        }
        //同步标签的时候传0
//        $currentSeq = $this->syncTaskMapper->getLatestCurrentSeq($corpId,$type,true);

        $syncTaskData = [
            'uid' => $params['uid'],
            'main_uid' => $params['main_uid'],
            'corp_id' => $corpId,
            'robot_id' => $robotInfo['id'],
            'type' => CorpTagTypeConstants::CORP,
        ];

        $syncTaskId = $this->syncTaskMapper->save($syncTaskData);

        return container()->get(Producer::class)->produce(new SyncTaskProducers(new SyncTaskDto(
            taskId: $syncTaskId,
            type: $type,
            className: __CLASS__,
            method: 'syncTag',
            currentSeq: 0
        )));
    }


    public function syncPersonalTag(array $params)
    {
        $robotIdList = explode(',',$params['robot_id']);

        $syncType = CorpTagTypeConstants::PERSONAL;
        foreach ($robotIdList as $robotId){
            if($this->syncTaskMapper->checkIsTaskInProgress($robotId,$syncType)){
                continue;
            }

            $robotInfo = $this->robotMapper->findById($robotId);
            $corpId = $robotInfo['corp_id'];
            //同步标签的时候传0
            $currentSeq = $this->syncTaskMapper->getLatestCurrentSeq($robotId,$syncType);

            $syncTaskData = [
                'uid' => $params['uid'],
                'main_uid' => $params['main_uid'],
                'corp_id' => $corpId,
                'robot_id' => $robotInfo['id'],
                'type' => $syncType,
            ];

            $syncTaskId = $this->syncTaskMapper->save($syncTaskData);
            container()->get(Producer::class)->produce(new SyncTaskProducers(new SyncTaskDto(
                taskId: $syncTaskId,
                type: $syncType,
                className: __CLASS__,
                method: 'syncTag',
                currentSeq: 0
            )));
        }
        return true;
    }

    public function syncTag($taskInfo, $currentSeq): bool
    {
        $taskId = $taskInfo['id'];
        $robotId = $taskInfo['robot_id'];
        $robotInfo = $this->robotMapper->findById($robotId);
        if(!$robotInfo['login_status']){
            $this->syncTaskMapper->update($taskId,[
                'status' => SyncTaskStatusConstants::FAILURE,
                'failure_reason' => '企微号离线'
            ]);
            return false;
        }

        $type = $taskInfo['type'];
        $corpId = $taskInfo['corp_id'];

        $robotApiService = make(Robot::class, [$robotInfo['server_id'], $robotInfo['uuid']])->gateway();
        $result = $robotApiService->getTagList($type, $currentSeq);
        if(empty($result)){
            $this->syncTaskMapper->update($taskId, [
                'status' => SyncTaskStatusConstants::FAILURE,
                'failure_reason' => $robotApiService->getErrorMsg()
            ]);
            return false;
        }

        $corpInfo = $this->corpMapper->findById($corpId);

        $labelList = $result['label_list'];
        if(!empty($labelList)){
            $corpTagData = collect($labelList)->map(function($item) use ($robotInfo,$type,$corpInfo){
                $item['id'] = $item['label_id'];
                $item['corp_id'] = $corpInfo->corp_id;
                if($type == SyncTaskTypeConstants::PERSONAL_TAG){
                    $item['robot_id'] = $robotInfo->id;
                    $item['owner_id'] = $robotInfo->user_id;
                }else{
                    $item['owner_id'] = $corpInfo->corp_id;
                }

                unset($item['label_id']);
                return $item;
            });

            $labelIdList = $corpTagData->pluck('id')->toArray();
            $existingLabelIdList = ChCorpTag::query()
                ->whereIn('id',$labelIdList)
                ->pluck('name','id');

            $toUpdate = $corpTagData->filter(fn($tag) => $existingLabelIdList->has($tag['id']));
            $toInsert = $corpTagData->reject(fn($tag) => $existingLabelIdList->has($tag['id']));

            if ($toUpdate->isNotEmpty()) {
                ChCorpTag::upsert($toUpdate->toArray(), ['id']);
            }

            if ($toInsert->isNotEmpty()) {
                ChCorpTag::insert($toInsert->toArray());
            }

            if($result['has_more']){
                return $this->syncTag($taskInfo,$result['current_seq']);
            }
        }

        $this->syncTaskMapper->update($taskId, [
            'extra' => [
                'current_seq' => $result['current_seq']
            ],
            'status' => SyncTaskStatusConstants::SUCCESS
        ]);
        return true;
    }

    /**
     * 新增个人标签
     * @param array $data
     * @return mixed
     */
    public function save(array $data): mixed
    {
        if($this->mapper->checkPersonalTagNameExist($data['robot_id'],$data['name'])){
            throw new NormalStatusException("名称已存在");
        }

        $robotInfo = $this->robotMapper->findById($data['robot_id']);
        if($robotInfo['login_status'] == 0) {
            throw new NormalStatusException('机器人离线，不能操作');
        }

        $robotApiService = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();

        $paramList = [
            [
                'labelId' => '',
                'labelSuperId' => $data['id'],
                'labelName' => $data['name'],
                'labelDataType' => 1
            ]
        ];

        $rst = $robotApiService->editLabel(ChCorpTag::OP_SAVE,$paramList);
        if($rst === false){
            throw new NormalStatusException($robotApiService->getErrorMsg());
        }
        $this->syncPersonalTag($data);
        return true;
    }

    /**
     * 更新标签
     * @param array $data
     * @return bool
     */
    public function updateTag(array $data):bool
    {
        $info = $this->mapper->findById($data['id']);
        if(empty($info)){
            throw new NormalStatusException('请选择您要编辑的标签');
        }

        if($this->mapper->checkPersonalTagNameExist($info->robot_id,$data['name'],$data['id'])){
            throw new NormalStatusException("名称已存在");
        }

        $robotInfo = $this->robotMapper->findById($info->robot_id);
        if($robotInfo['login_status'] == 0) {
            throw new NormalStatusException('机器人离线，不能操作');
        }

        $robotApiService = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();

        $paramList = [
            [
                'labelId' => $data['id'],
                'labelSuperId' => $info->group_id,
                'labelName' => $data['name'],
            ]
        ];
        $result = $robotApiService->editLabel(ChCorpTag::OP_UPDATE,$paramList);
        if($result === false){
            throw new NormalStatusException($robotApiService->getErrorMsg());
        }

        $info->name = $data['name'];
        return $info->save();
    }

    public function deleteTag(array $data):bool
    {
        $info = $this->mapper->findById($data['id']);
        if(empty($info)){
            throw new NormalStatusException('请选择您要删除的标签');
        }
        $robotInfo = $this->robotMapper->findById($info->robot_id);
        if($robotInfo['login_status'] == 0) {
            throw new NormalStatusException('机器人离线，不能操作');
        }

        $robotApiService = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();

        $paramList = [
            [
                'labelId' => $data['id'],
                'labelSuperId' => $info->group_id,
                'labelName' => '',
            ]
        ];
        $rst = $robotApiService->editLabel(ChCorpTag::OP_DELETE,$paramList);
        if ($rst === false){
            throw new NormalStatusException($robotApiService->getErrorMsg());
        }
        return $info->delete();
    }

    /**
     * 添加客户标签关联
     * @param array $data
     * @return bool
     */
    public function addContact(array $data): bool
    {
        $id = $data['id'];
        $contactId = json_decode($data['contact_ids'],true);

        $model = $this->mapper->findById($id);
        if(empty($model)){
            throw new NormalStatusException('添加失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setTagIds([$id]);

        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::PUT_ON_CORP_TAG,$content);
    }

    /**
     * 标签里删除客户
     * @param array $data
     * @return bool
     */
    public function delContact(array $data): bool
    {
        $id = $data['id'];
        $contactId = json_decode($data['contact_ids'],true);

        $model = $this->mapper->findById($id);;
        if(empty($model)){
            throw new NormalStatusException('删除失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setRemoveTagIds([$id]);

        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::DELETE_CORP_TAG,$content);
    }

    /**
     * 移动客户
     * @param array $data
     * @return bool
     */
    public function moveContact(array $data): bool
    {
        $id = $data['remove_id'];
        $moveTagIds = json_decode($data['move_tag_ids'],true);
        $contactId = json_decode($data['contact_ids'],true);

        $model = $this->mapper->findById($id);
        if(empty($model)){
            throw new NormalStatusException('移动失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setTagIds($moveTagIds);
        $content->setRemoveTagIds([$id]);

        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::MOVE_CORP_TAG,$content);
    }

    /**
     * 添加新的标签
     * @param array $data
     * @return bool
     */
    public function setCorpTag(array $data): bool
    {
        $contactIds = json_decode($data['contact_ids'],true);
        $tagIds = json_decode($data['ids'],true);
        $content = new ContactTcContentDto();
        $content->setContactIds($contactIds);
        $content->setTagIds($tagIds);
        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::PUT_ON_CORP_TAG,$content);
    }


    public function getTagsByIds($ids)
    {
        $placeholders = implode(',', array_fill(0, count($ids), '?'));
        return $this->mapper->getModel() ->  newQuery() ->whereRaw("`id` IN ({$placeholders})", $ids)
            -> pluck('name');
    }

    /**
     *
     * @param array $contactIds
     * @param array $tagIds
     * @param array $removeTagIds
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function updateCorpTagContactCnt(array $contactIds,array $tagIds,array $removeTagIds = []): void
    {
        $contactCnt = count($contactIds);
        $corpTagMapper = container()->get(ChCorpTagMapper::class);
        if(!empty($tagIds)){
            $corpTagMapper->updateContactCnt($tagIds,$contactCnt);
            event(new ContactOperationBehaviorAfter($contactIds,ContactBehaviorTypeConstants::CHANGE_TAG,[
                'tagIds' => $tagIds,
                'isAdd' => true,
                'isCorpTags' => true
            ]));
        }

        if(!empty($removeTagIds)){
            $corpTagMapper->updateContactCnt($removeTagIds,-$contactCnt);
            event(new ContactOperationBehaviorAfter($contactIds,ContactBehaviorTypeConstants::CHANGE_TAG,[
                'tagIds' => $removeTagIds,
                'isAdd' => false,
                'isCorpTags' => true
            ]));
        }
    }
}